package by.apiskun.curex.dataaccess.impl;

import java.util.Date;
import java.util.List;

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.Validate;
import org.springframework.stereotype.Repository;

import by.apiskun.curex.dataaccess.ChangeRateDAO;
import by.apiskun.curex.datamodel.ChangeRate;
import by.apiskun.curex.datamodel.ChangeRate_;
import by.apiskun.curex.datamodel.Money_;

@Repository
public class ChangeRateDAOImpl extends AbstractDAOImpl<Long, ChangeRate>
		implements ChangeRateDAO {
	protected ChangeRateDAOImpl() {
		super(ChangeRate.class);
	}

	@Override
	public ChangeRate getById(Long id) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<ChangeRate> criteria = cBuilder
				.createQuery(ChangeRate.class);
		Root<ChangeRate> root = criteria.from(ChangeRate.class);

		criteria.select(root);
		root.fetch(ChangeRate_.moneyNameBefore);
		root.fetch(ChangeRate_.moneyNameAfter);
		criteria.distinct(true);

		TypedQuery<ChangeRate> query = getEm().createQuery(criteria);

		return query.getSingleResult();

	}

	@Override
	public Long getCount() {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
		Root<ChangeRate> root = criteria.from(ChangeRate.class);

		criteria.select(cBuilder.count(root));

		TypedQuery<Long> query = getEm().createQuery(criteria);
		return query.getSingleResult();
	}

	@Override
	public List<ChangeRate> getAllChangeRates() {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<ChangeRate> criteria = cBuilder
				.createQuery(ChangeRate.class);
		Root<ChangeRate> root = criteria.from(ChangeRate.class);

		criteria.select(root);

		TypedQuery<ChangeRate> query = getEm().createQuery(criteria);
		List<ChangeRate> results = query.getResultList();
		return results;
	}

	@Override
	public void updateChangeRateCourse(Long id, Double newCourse) {
		String q = String
				.format("update from %s p set p.changeRateCourse=:newParam where p.id=:id",
						ChangeRate.class.getSimpleName());
		Query updateQuery = getEm().createQuery(q);
		updateQuery.setParameter("newParam", newCourse);
		updateQuery.setParameter("id", id);
		int updatedRowsCount = updateQuery.executeUpdate();
		Validate.isTrue(updatedRowsCount == 1, "One row should be updated");

	}

	@Override
	public void updateChangeRateEndDate(Long id, Date newEndDate) {
		String q = String.format(
				"update from %s p set p.endDate=:newParam where p.id=:id",
				ChangeRate.class.getSimpleName());
		Query updateQuery = getEm().createQuery(q);
		updateQuery.setParameter("newParam", newEndDate);
		updateQuery.setParameter("id", id);
		int updatedRowsCount = updateQuery.executeUpdate();
		Validate.isTrue(updatedRowsCount == 1, "One row should be updated");

	}

	@Override
	public List<ChangeRate> getAllChangeRatesByBeforeName(String beforeName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<ChangeRate> root = cBuilder.createQuery(ChangeRate.class);
		Root<ChangeRate> criteria = root.from(ChangeRate.class);

		root.select(criteria);
		criteria.fetch(ChangeRate_.moneyNameBefore);
		root.distinct(true);
		root.where(cBuilder.equal(criteria.get(ChangeRate_.moneyNameBefore)
				.get(Money_.moneyName), beforeName));

		TypedQuery<ChangeRate> query = getEm().createQuery(root);
		List<ChangeRate> results = query.getResultList();
		return results;
	}

	@Override
	public List<ChangeRate> getAllChangeRatesByAfterName(String afterName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<ChangeRate> root = cBuilder.createQuery(ChangeRate.class);
		Root<ChangeRate> criteria = root.from(ChangeRate.class);

		root.select(criteria);
		criteria.fetch(ChangeRate_.moneyNameAfter);
		root.distinct(true);
		root.where(cBuilder.equal(
				criteria.get(ChangeRate_.moneyNameAfter).get(Money_.moneyName),
				afterName));

		TypedQuery<ChangeRate> query = getEm().createQuery(root);
		List<ChangeRate> results = query.getResultList();
		return results;
	}

	@Override
	public List<ChangeRate> getAllChangeRatesForDay(Date date) {
		// TODO Auto-generated method stub
		return null;
	}

}
